package cn.superfw.controller;

import cn.superfw.common.ApiResource;
import cn.superfw.common.dto.CityDto;
import cn.superfw.domain.model.*;
import cn.superfw.domain.repository.CityRepositoryDsl;
import cn.superfw.domain.repository.OrderRepositoryDsl;
import cn.superfw.domain.repository.StoreRepositoryDsl;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.security.Principal;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

@SuppressWarnings("ALL")
@Api(value = "/", tags = "测试接口")
@RestController
@RequestMapping("/")
public class DummyController {

    @Autowired
    CityRepositoryDsl cityRepositoryDsl;

    @Autowired
    OrderRepositoryDsl orderRepositoryDsl;

    @Autowired
    StoreRepositoryDsl storeRepositoryDsl;

    @Autowired
    JPAQueryFactory queryFactory;

    @RequestMapping(method = RequestMethod.GET)
    public String helloWorld(Principal principal) {
        return principal == null ? "Hello anonymous" : "Hello " + principal.getName();
    }

    @PreAuthorize("#oauth2.hasScope('openid') and hasRole('ROLE_ADMIN')")
    @RequestMapping(value = "secret", method = RequestMethod.GET)
    public String helloSecret(Principal principal) {
        return principal == null ? "Hello anonymous" : "S3CR3T  - Hello " + principal.getName();
    }

    @ApiOperation(value = "初始化数据", notes = "生成一堆假数据。")
    @GetMapping("init-data")
    @Transactional
    public ApiResource<String> initDummyData() {
        // 城市信息
        QCity city = QCity.city;
        queryFactory.delete(city).execute();
        String[][] cityData = {{"010", "北京", "首都"}, {"021", "上海", "直辖市"}, {"022", "天津", "直辖市"}, {"023", "重庆", "直辖市"},
                {"311", "河北", "行政省"}, {"351", "山西", "行政省"}, {"371", "河南", "行政省"}, {"024", "辽宁", "行政省"},
                {"531", "山东", "行政省"}, {"020", "广东", "行政省"}, {"871", "云南", "行政省"}, {"591", "福建", "行政省"}};
        Arrays.stream(cityData).forEach(cityInfo -> cityRepositoryDsl.saveAndFlush(new City(cityInfo[0], cityInfo[1], cityInfo[2])));


        // 订单信息
        List<Order> orders = orderRepositoryDsl.findAll();
        orders.forEach(order -> {
            order.getOrderItems().clear(); // 解除关系
            orderRepositoryDsl.delete(order); // 删除主表，自动级联删除子表
        });

        QOrder order = QOrder.order;
        Order order1 = new Order();
        order1.setOrderNo("ORD-11111-22222");
        order1.setOrderStatus(20);
        order1.setCreatedTime(new Timestamp(System.currentTimeMillis()));
        order1.setCreatedBy("U0001");

        OrderItem orderItem1 = new OrderItem(order1); // 建立关系
        orderItem1.setProductName("ThinkPad T470P");
        orderItem1.setProductPrice(BigDecimal.valueOf(13600));
        orderItem1.setNumber(3);
        orderItem1.setSubtotal(orderItem1.getProductPrice().multiply(BigDecimal.valueOf(orderItem1.getNumber())));

        OrderItem orderItem2 = new OrderItem(order1); // 建立关系
        orderItem2.setProductName("MacBook Pro 1345");
        orderItem2.setProductPrice(BigDecimal.valueOf(24600));
        orderItem2.setNumber(5);
        orderItem2.setSubtotal(orderItem2.getProductPrice().multiply(BigDecimal.valueOf(orderItem2.getNumber())));

        order1.getOrderItems().add(orderItem1); // 建立关系
        order1.getOrderItems().add(orderItem2); // 建立关系

        orderRepositoryDsl.saveAndFlush(order1);


        // 店铺信息
        storeRepositoryDsl.findAll().forEach(store -> {
            store.getStoreDetails().setStore(null); // 解除关系
            storeRepositoryDsl.delete(store); // 删除主表，自动级联删除子表
        });
        Store store = new Store("S0000001","京东数码旗舰店");
        store.setStoreDetails(new StoreDetails("superch", "13702156454"));
        storeRepositoryDsl.saveAndFlush(store);

        return new ApiResource.Builder().coce("OK").result("OK").build();
    }

    @ApiOperation(value = "创建城市", notes = "如果数据库中存在区号为022的城市则更新城市描述，否则新建城市。")
    @GetMapping("add-city")
    @Transactional
    public ApiResource<List<CityDto>> addCity() {

        QCity city = QCity.city;
        // 件数检查
        long count = queryFactory.from(city).where(city.cityCode.eq("022")).fetchCount();
        if (count == 0) {
            // 执行插入操作
            City newCity = new City();
            newCity.setCityCode("022");
            newCity.setCityName("天津");
            newCity.setCityDes("直辖市");
            cityRepositoryDsl.save(newCity);

            // 执行更新操作
        } else {
            queryFactory
                    .update(city)
                    .set(city.cityDes, "直辖市" + UUID.randomUUID().toString())
                    .where(city.cityCode.eq("022"))
                    .execute();
        }

        // 执行再检索
        ApiResource<List<CityDto>> apiResource = echoCity("022", null, null);
        return apiResource;
    }

    @ApiOperation(value = "获取城市信息")
    @GetMapping("echo-city")
    public ApiResource<List<CityDto>> echoCity(
            @ApiParam(value = "城市代码") @RequestParam(required = false) String cityCode,
            @ApiParam(value = "分页检索偏移量", defaultValue = "0") @RequestParam(required = false) Long offset,
            @ApiParam(value = "分页检索件数", defaultValue = "5") @RequestParam(required = false) Long limit) {

        QCity city = QCity.city;

        BooleanExpression whereExpression = city.id.eq(city.id);
        if (cityCode != null) {
            whereExpression = whereExpression.and(city.cityCode.eq(cityCode));
        }

        List<CityDto> cityResource = queryFactory
                .select(Projections.bean(CityDto.class, city.id, city.cityCode, city.cityName, city.cityDes)) // 装配结果集
                .from(city)
                .where(whereExpression)
                .orderBy(city.cityCode.asc())
                .offset(offset == null ? 0 : offset)
                .limit(limit == null ? 5 : limit)
                .fetch();
        ApiResource apiResource = new ApiResource.Builder().result(cityResource).build();
        return apiResource;
    }

    @ApiOperation(value = "查询订单", notes = "一对多动态条件查询，并且条件限定出现在多的一端的情况的示例。" +
            "[订单编号]是订单表的字段，[商品名称]时订单条目表的字段，订单和订单条目时一对多的关系。")
    @GetMapping("search-order")
    public ApiResource<List<Order>> searchOrder(
            @ApiParam(value = "订单编号") @RequestParam(required = false) String orderNo,
            @ApiParam(value = "商品名称") @RequestParam(required = false) String productName,
            @ApiParam(value = "分页检索偏移量", defaultValue = "0") @RequestParam(required = false) Long offset,
            @ApiParam(value = "分页检索件数", defaultValue = "5") @RequestParam(required = false) Long limit) {

        QOrder order = QOrder.order;
        QOrderItem orderItem = QOrderItem.orderItem;

        // 构建动态Where条件
        BooleanExpression whereExpression = order.commonId.eq(order.commonId) ;
        if (orderNo != null) {
            whereExpression = whereExpression.and(order.orderNo.eq(orderNo));
        }
        if (productName != null) {
            whereExpression = whereExpression.and(orderItem.productName.eq(productName));
        }

        // 执行检索
        List<Order> orders = queryFactory
                .selectFrom(order)  // 注意：只有用selectFrom才会自动将结果集组装Order实体
                .leftJoin(order.orderItems, orderItem) // 注意：连接的写法，第二个参数很重要
                .where(whereExpression) // whereExpression==null时自动不拼接where语句
                .offset(offset == null ? 0 : offset)
                .limit(limit == null ? 5 : limit)
                .distinct()
                .fetch();

        return new ApiResource.Builder().result(orders).build();
    }

    @ApiOperation(value = "显示店铺信息", notes = "一对一级联查询的例子")
    @GetMapping("echo-store")
    public ApiResource<List<Store>> echoStore() {
        List<Store> stores = queryFactory.selectFrom(QStore.store).fetch();
        return new ApiResource.Builder().result(stores).build();
    }

}
